package io.openmessaging.map;

import io.openmessaging.Conf;
import io.openmessaging.utils.ArrayUtils;
import io.openmessaging.utils.Assert;

/**
 * 队列中消息的 offset 的索引
 * 通常和 TopicQueueMap 组合使用
 */
public class OffsetMap<E> {
    private Object[][][][] data = new Object[256][][][];

    public E set(long offset, E e) {
        //每个消息至少100B，总共125GB数据，最多 125GB/100B = 1.25G 个消息，所以offset使用4字节储存足够
        Assert.isTrue(offset < Conf.maxOffset, "offset 过大：", offset);
        int i = (int) offset;//避免后面频繁类型转换

        int i1 = i >> 24;// <==> i >> 24  & 0xff
        Object[][][] offset1 = ArrayUtils.computeIfAbsent(data, i1, () -> new Object[256][][]);

        int i2 = (i >> 16) & 0xff;
        Object[][] offset2 = ArrayUtils.computeIfAbsent(offset1, i2, () -> new Object[256][]);

        int i3 = (i >> 8) & 0xff;
        Object[] offset3 = ArrayUtils.computeIfAbsent(offset2, i3, () -> new Object[256]);
        offset3[i & 0xff] = e;
        return e;
    }

    public E get(long offset) {
        if (offset > Conf.maxOffset)
            return null;

        int i = (int) offset;//避免后面频繁类型转换

        int i1 = i >> 24;
        Object[][][] offset1 = data[i1];
        if (offset1 == null)
            return null;

        int i2 = (i >> 16) & 0xff;
        Object[][] offset2 = offset1[i2];
        if (offset2 == null)
            return null;

        int i3 = (i >> 8) & 0xff;
        Object[] offset3 = offset2[i3];
        if (offset3 == null)
            return null;

        return (E) offset3[i & 0xff];
    }
}
